#!/usr/bin/env python
#############################################################################
#                                                                           #
#   File: /serverA/main.py                                                  #
#                                                                           #
#   Copyright (C) 2010-2011                                                 #
#                                                                           #
#   Home: http://code.google.com/p/you-proxy/                               #
#                                                                           #
#   This file is part of ezcryptohttpproxy.                                 #
#                                                                           #
#                                                                           #
#   ezcryptohttpproxy is free software: you can redistribute it and/or      #
#   modify it under the terms of the GNU General Public License as          #
#   published by the Free Software Foundation, either version 3 of the      #
#   License, or (at your option) any later version.                         #
#                                                                           #
#   wallproxy-fixed is distributed in the hope that it will be useful,      #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of          #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           #
#   GNU General Public License for more details.                            #
#                                                                           #
#   You should have received a copy of the GNU General Public License       #
#   along with ezcryptohttpproxy.                                           #
#   If not, see <http://www.gnu.org/licenses/>                              #
#                                                                           #
#############################################################################

__version__ = '0.0.1'
__author__ = 'OHU2REFJQGdtYWlsLmNvbQ=='.decode('base64')

import socket, thread, select,traceback,sys,os
import threading
from time import sleep
BUFLEN = 8192
VERSION = 'ezcryptohttpproxy/'+__version__
HTTPVER = 'HTTP/1.1'

#-------------default value of serverA.conf--------------------------
listen = ('',8080);
serverB = ('localhost',8081);
serverBaddrinfo = None;

isencode = False

class cryptography:
  #please init key and something others 
  def __init__(self):
    return
  def encode(self,data):
  #encode data that send to serverB
    return data;
  def decode(self,data):
  #decode data that recv from serverB
    return data
#---------------------------------------end--------------------------

class handler:
  def __init__(self,client,address,timeout):
    global serverB,serverBaddrinfo;
    #connect serverB
    self.rawbuffer = ''
    soc_family = serverBaddrinfo[0];
    address = serverBaddrinfo[4];
    self.target = socket.socket(soc_family);
    self.target.connect(address);
    self.client = client

    if isencode==False:
      self.recv_decode = self.target.recv;
      self.send_encode = self.target.send;
    else:
      self.crypto = cryptography();
    #read_write
    time_out_max = timeout/3
    socs = [self.client, self.target]
    count = 0
    while 1:
      count += 1
      (recv, _, error) = select.select(socs, [], socs, 3)
      if error:
        break
      if recv:
        for in_ in recv:
          if in_ is self.target:
            data = self.recv_decode(BUFLEN)
            if data:
              self.client.send(data)
              count = 0;
          elif in_ is self.client:
            data = self.client.recv(BUFLEN)
            if data:   
              self.send_encode(data)
              count = 0
      if count == time_out_max:
        break
    #close socket.
    self.client.close();
    self.target.close();
    
    #function here need to care about data size,at last one chunked
  def recv_decode(self,size=-1):
    #try to return one chunked.
    #donot care about recv how many bytes
      while (1):
        i = self.rawbuffer.find('\n')
        if i != -1:
          try:
            size = int(self.rawbuffer[:i],16)
            if ((i+1+size)<=len(self.rawbuffer)):
              recvget = self.rawbuffer[i+1:i+1+size]
              self.rawbuffer = self.rawbuffer[i+1+size:]
              return self.crypto.decode(recvget)
          except ValueError:
            self.target.send("\n\nWrong format!\n");
            raise ValueError
        tmp = self.target.recv(size);
        if (tmp==''):
          return ''
        self.rawbuffer +=tmp

  def send_encode(self,data):
      if data=='':return 
      data = self.crypto.encode(data);
      length=hex(len(data)).strip('L')[2:]
      self.target.send(length+'\n'+data)

isserverlive = 1;
__is_shut_down = 0;
def start_server(host='localhost', port=8080, IPv6=False, timeout=60,
                  handler=handler):
    global isserverlive,__is_shut_down
    if IPv6==True:
        soc_type=socket.AF_INET6
    else:
        soc_type=socket.AF_INET
    soc = socket.socket(soc_type)
    soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    soc.bind((host, port))
    print "Serving on %s:%d."%(host, port)#debug
    soc.listen(0)
    __is_shut_down = 0;
    while 1:
      arg=soc.accept()+(timeout,)
      if (isserverlive==0):
        arg[0].close()
        break;
      t = threading.Thread(target = handler,args = arg)
      t.setDaemon (1)
      t.start() 
      del t
    soc.shutdown(socket.SHUT_RDWR)
    soc.close()
    print 'start_server ended'
    __is_shut_down = 1;

def shutdown(host='localhost', port=8080,IPv6=False):
    global isserverlive,__is_shut_down
    isserverlive = 0;
    if IPv6==True:
        soc_type=socket.AF_INET6
    else:
        soc_type=socket.AF_INET
    target = socket.socket(soc_type)
    try:
      target.connect((host, port))
      target.close();
    except:
      pass
    while(1):
      sleep(0.2)
      if (__is_shut_down==1):return;
    
    
def taskother():
    from time import sleep
    try:
      while(1):sleep(1)
    except KeyboardInterrupt:
      shutdown(listen[0],listen[1])

if __name__ == '__main__':
  try:
    path = os.path.dirname(os.path.abspath(sys.argv[0]))
    execfile(os.path.join(path,'serverA.conf') )
  except:
    traceback.print_exc();
  serverBaddrinfo = socket.getaddrinfo(serverB[0],serverB[1])[0];
  print 'serverB:',serverBaddrinfo
  print listen
  threading.Thread(target = start_server,args = (listen[0],listen[1])).start()
  taskother();
